#pragma once

#include <cmath>
#include <list>

#include "LBM.h"

struct Particle
{
  LBfloat x, y;
};

class ParticleSystem
{
private:
  typedef std::list<Particle> Particles;

  const LatticeBoltzmannD2Q7 & m_ca;
  Particles m_particles;

public:
  typedef Particles::const_iterator const_iterator;

  ParticleSystem(const LatticeBoltzmannD2Q7 & ca) : m_ca(ca) {}

  size_t getCount() const { return m_particles.size(); }

  bool addParticle(LBfloat x, LBfloat y) {
    Particle p;
    p.x = x;
    p.y = y;

    int xi = (int)p.x;
    int yi = (int)p.y;
    if ( xi >= 0 && yi >= 0 && xi < m_ca.getWidth() && yi < m_ca.getHeight() )
      if ( m_ca.getCellType(xi, yi) != CELL_WALL )
      {
        m_particles.push_back(p); 
        return true;
      }
    return false;
  }

  const_iterator begin() const { return m_particles.begin(); }
  const_iterator end() const { return m_particles.end(); }

  void iterate()
  {
    int width = m_ca.getWidth();
    int height = m_ca.getWidth();

    Particles::iterator iter = m_particles.begin();
    while ( iter != m_particles.end() )
    {
      int xi = (int)iter->x;
      int yi = (int)iter->y;

      LBfloat ux, uy;
      calcVelocity(m_ca.getCell(xi, yi), ux, uy);
      iter->x += ux;
      iter->y += uy / CellHeight;

      xi = (int)iter->x;
      yi = (int)iter->y;
      if ( xi < 0 || yi < 0 || xi >= width || yi >= height )
        iter = m_particles.erase(iter);
      else
        ++iter;
    }
  }
};